# -*- coding:utf8 -*-
import json
import traceback
import os
import typing
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64
import requests
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from scrapy import Request
from squirrel_core.commons.utils.tools import calc_str_md5, upload_file
from squirrel_core.frame.spider_makaka import MakakaSpider

file_path = os.environ.get("FILE_PATH", "/")


class meipaipai_pic(MakakaSpider):
    name = "meipaipai_pic"
    race_url = "https://api.meipaipai.cn/v5/api/storage/clip/template/matches/{}/projects"
    search_url = "https://api.meipaipai.cn/v5/api/storage/clip/template/matches/applet?pageNum=1&name={}"
    video_url = "https://api.meipaipai.cn/v5/api/storage/clip/template/matches/projects/{}/result?param={}"
    serialNumber = ""
    all_flag = False
    need_ssdbstore_dup = True
    header = {"client": "pc_admin"}

    def get_ext_requests_or_urls(self, data=None):
        if data and isinstance(data, str):
            data = json.loads(data)
        if data and isinstance(data, typing.MutableMapping):
            self.serialNumber = data.get("serialNumber", "")
            self.all_flag = data.get("spider_config", {}).get("all", False)
            race_id = data.get("spider_config", {}).get("race_id", "")
            user_id = data.get("spider_config", {}).get("user_id", "")
            race_no = data.get("spider_config", {}).get("race_no", "")
            race_name = data.get("spider_config", {}).get("race_name", "")
            race_item = data.get("spider_config", {}).get("race_item", "")
            if not all([race_id, user_id, race_no, race_name, race_item]):
                self.logger.info("参数不全，请仔细核对")
                self.upload_procedure({"serialNumber": self.serialNumber, "code": 101, "message": "参数不全，请仔细核对"})
                self.close_after_idle = True
                self.force_to_close_spider = True
            else:
                self.upload_procedure({"serialNumber": self.serialNumber, "code": 100, "message": "任务启动成功"})
                search_url = self.search_url.format(race_name)
                yield Request(url=search_url, callback=self.parse, dont_filter=True, errback=self.err_parse,
                              headers=self.header, meta={"race_item": race_item, "race_no": race_no, "user_id": user_id,
                                                         "race_name": race_name, "race_id": race_id})

    def parse(self, response, **kwargs):
        race_item = response.meta.get("race_item", "")
        race_no = response.meta.get("race_no", "")
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_name = response.meta.get("race_name", "")
        try:
            self.logger.info(f"开始解析race_id：{race_name}")
            content = json.loads(response.text)
            secret_key = content.get("secretKey", "")
            secret_key = self.decrypt_rsa(secret_key)
            data_str = content.get("result", "")
            data_str = self.decrypt(data_str, secret_key)
            data_dict = json.loads(data_str)
            data_list = data_dict.get("data", [])
            if data_list:
                r_id = data_list[0].get("id", "")
                race_url = self.race_url.format(r_id)
                yield Request(url=race_url, callback=self.parse_race, dont_filter=True, errback=self.err_parse,
                              headers=self.header,
                              meta={"race_item": race_item, "race_no": race_no, "race_name": race_name,
                                    "user_id": user_id, "race_id": race_id})
        except Exception:
            self.logger.info(f"解析{race_name}的race_id时出错：{traceback.format_exc()}")

    def parse_race(self, response):
        race_item = response.meta.get("race_item", "")
        race_no = response.meta.get("race_no", "")
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_name = response.meta.get("race_name", "")
        try:
            self.logger.info(f"开始解析race_item_id")
            content = json.loads(response.text)
            secret_key = content.get("secretKey", "")
            secret_key = self.decrypt_rsa(secret_key)
            data_str = content.get("result", "")
            data_str = self.decrypt(data_str, secret_key)
            data_list = json.loads(data_str)
            for data in data_list:
                if race_item == data.get("name", ""):
                    race_item_id = data.get("id", "")
                    video_url = self.video_url.format(race_item_id, race_no)
                    yield Request(url=video_url, callback=self.parse_video, errback=self.err_parse,
                                  dont_filter=True, headers=self.header,
                                  meta={"race_item": race_item, "race_no": race_no, "race_name": race_name,
                                        "race_id": race_id, "user_id": user_id})
        except Exception:
            self.logger.info(f"解析race_item_id时出错：{traceback.format_exc()}")

    def parse_video(self, response):
        race_no = response.meta.get("race_no", "")
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        try:
            self.logger.info(f"开始解析视频")
            content = json.loads(response.text)
            secret_key = content.get("secretKey", "")
            secret_key = self.decrypt_rsa(secret_key)
            data_str = content.get("result", "")
            data_str = self.decrypt(data_str, secret_key)
            content = json.loads(data_str)
            files = content[0].get("files", [])
            for file in files:
                url = file.get("url", "")
                pic_md5 = calc_str_md5(url)
                pic_name = f"{race_no}_{pic_md5}.mp4"
                dir_path = os.path.join(file_path, self.name_first)
                if not os.path.exists(dir_path):
                    os.makedirs(dir_path)
                save_path = os.path.join(dir_path, pic_name)
                if not os.path.exists(save_path):
                    with requests.get(url, stream=True) as r:
                        r.raise_for_status()
                        with open(save_path, 'wb') as f:
                            for chunk in r.iter_content(chunk_size=1024*24):
                                f.write(chunk)
                    upload_path = f"flow/{race_id}/{user_id}/pic/{pic_name}"
                    upload_flag = upload_file(save_path, upload_path)
                    if upload_flag:
                        self.logger.info(f"{save_path}上传成功：{upload_path}")
                    else:
                        self.logger.info(f"{save_path}上传失败：{upload_path}")
                    result_dict = {"url_address": upload_path, "race_no": race_no}
                    result = self.send_data(resp=response, serial_number=self.serialNumber, result_data=result_dict,
                                            user_id=user_id, race_id=race_id, dup_str=str(result_dict))
                    yield result
        except Exception:
            self.logger.info(f"开始解析视频时出错：{traceback.format_exc()}")

    def send_data(self, resp=None, serial_number=None, result_data=None, user_id=None, race_id=None, dup_str=None):
        if result_data is None:
            result_data = {"msg": "未查到照片信息"}
        result_dict = {"serialNumber": serial_number, "webType": self.name_first,
                       "userId": user_id, "raceId": race_id, "code": 200,
                       "crawlerType": self.name_second, "data": str(result_data)}
        result = self.result_item_assembler(resp)
        result['result_data'] = result_dict
        if not self.all_flag and dup_str is not None:
            result['_dup_str'] = calc_str_md5(dup_str)
        return result

    def err_parse(self, failure):
        self.logger.warning(f"请求失败：{failure.request.url},错误原因:{traceback.format_exc()}")

    def decrypt_rsa(self, encrypted_data):
        private_key_pem = """-----BEGIN PRIVATE KEY-----
    MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKPDC+DzAWUW4ZiY
    OivffGOYljLXzYN6+4sZopfNUVgiv/7L9jF+p5d6+SD7q3den8hTCU0degvnw6jS
    MYrBmZe8Da4HsPpaJROXNT9Z2zCBLWymjy+1CRW8olXjZlkOdPENTzD0pSPLBoQP
    CEfviFrBweB9kNXIbxuDcS5TsJLFAgMBAAECgYBbUzaYqGwqt+vvcVVfii6QTFPW
    3spZfIgzNoSaK4IlqJtxuMT/LSbBL28nmbIxy69HxCb3vmyFnyZaS34dZ4IDWpAP
    xs+3y6dqAW0el2q34anlSvvoaHbqrtCuHkeFPttIWelx4C/apPHI2DMzHL44KY3N
    DyhvFmBY1ykGdWRYAQJBAOXrDbpxTg4iyJUfzYa/ef97rxHBi3ymez9Ban+BTowF
    IWp/kftBk8cSv5ba9Qdl85w0yl4kpEMCLvF0Xf21lYECQQC2Vsd6jqpXDbZzeoFX
    w5n0IpqqLC2lS7DWAPrAV6pyhNSAs1o06jmaPMw3bWCxJ2I+wOa82FO2H+iC2ERe
    iMdFAkEAoIolNtcg2ov9JOtk9j7C79qsHqjXPf19N2j09P0UHH8EmzlidF+Q0UNN
    FgfjafwNQzg1SdEqBUQEBULs0le1gQJACNHVwEXaU2+kXZ2VWAtsDPUHiies5Yvt
    t8xAVMFoyzVFmhwSxvB1bNJ4Bk5SGP+QrvxhrMzB79NHSdzwIap4CQJBAKrXIo56
    bG6ECcms9+yyY5MC7dniaXU9mhMVjlvRhTWZ8PvT/CvBOm8kK0dwNOl3ZtMmJGRO
    chU29iJzUVBIWQU=
    -----END PRIVATE KEY-----"""
        try:
            private_key = RSA.import_key(private_key_pem)
            cipher = PKCS1_v1_5.new(private_key)
            encrypted_bytes = base64.b64decode(encrypted_data)
            decrypted = cipher.decrypt(encrypted_bytes, None)
            if decrypted is None:
                raise ValueError("解密失败：可能是密钥不匹配或数据损坏")
            return decrypted.decode('utf-8')
        except ValueError as e:
            try:
                from Crypto.Util.asn1 import DerSequence
                from Crypto.IO import PEM
                pkcs8_der = PEM.decode(private_key_pem)[0]
                private_key_der = DerSequence()
                private_key_der.decode(pkcs8_der)
                pkcs1_der = private_key_der[2]
                pkcs1_pem = PEM.encode(pkcs1_der, "RSA PRIVATE KEY")
                private_key = RSA.import_key(pkcs1_pem)
                cipher = PKCS1_v1_5.new(private_key)
                decrypted = cipher.decrypt(encrypted_bytes, None)
                return decrypted.decode('utf-8')
            except Exception as e:
                return None

    def decrypt(self, r, t="abcdefgabcdefg12"):
        key = t.encode('utf-8')
        cipher = AES.new(key, AES.MODE_ECB)
        decrypted = cipher.decrypt(base64.b64decode(r))
        unpadded = unpad(decrypted, AES.block_size)
        return unpadded.decode('utf-8')
